#ifndef SHAREDMEMORY_H_
#define SHAREDMEMORY_H_

#define SHM_OK			0
#define	ERROR_FTOK		-1
#define ERROR_SHMGET	-2
#define	ERROR_SHMAT		-3

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>

template<class T> class SharedMemory {

private:
	int shmId;
	T* dataPtr;

	int attachedProcesses();

public:
	SharedMemory();
	~SharedMemory();
	int create (char *file, int id);
	void free();
	void write(T data);
	T read();
};

template<class T> SharedMemory<T>::SharedMemory() {
}

template<class T> SharedMemory<T>::~SharedMemory() {
}

template<class T> int SharedMemory<T>::create(char *file, int id) {
	// generacion de la clave
	key_t key = ftok(file, id);
	if ( key == -1 )
		return ERROR_FTOK;
	else {
		// creacion de la memoria compartida
		this->shmId = shmget(key, sizeof(T), 0644|IPC_CREAT );

		if ( this->shmId == -1 )
			return ERROR_SHMGET;
		else {
			// attach del bloque de memoria al espacio de direcciones del proceso
			void* tempPtr = shmat(this->shmId, NULL, 0);

			if (tempPtr == (void *)-1) {
				return ERROR_SHMAT;
			} else {
				this->dataPtr = (T*)tempPtr;
				return SHM_OK;
			}
		}
	}
}

template<class T> void SharedMemory<T>::free() {
	// detach del bloque de memoria
	shmdt((void*)this->dataPtr);

	int attachedProc = this->attachedProcesses();

	if(attachedProc == 0) {
		shmctl(this->shmId, IPC_RMID, NULL);
	}
}

template<class T> void SharedMemory<T>::write(T data) {
	*(this->dataPtr) = data;
}

template<class T> T SharedMemory<T>::read() {
	return (*(this->dataPtr));
}

template <class T> int SharedMemory<T>::attachedProcesses() {
	shmid_ds status;
	shmctl(this->shmId, IPC_STAT, &status );
	return status.shm_nattch;
}

#endif /* SHAREDMEMORY_H_ */
